package com.duke.finca.web;

import java.io.InputStream;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JRExporter;
import net.sf.jasperreports.engine.JRExporterParameter;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.data.JRBeanCollectionDataSource;
import net.sf.jasperreports.engine.export.JRHtmlExporter;
import net.sf.jasperreports.engine.export.JRHtmlExporterParameter;
import net.sf.jasperreports.engine.export.JRPdfExporter;
import net.sf.jasperreports.engine.export.JRXlsExporter;
import net.sf.jasperreports.engine.export.JRXlsExporterParameter;
import net.sf.jasperreports.j2ee.servlets.ImageServlet;

import org.apache.log4j.Logger;

import com.duke.finca.util.ConstantWebApp;

public class GenericReportAction  {

	private static final long serialVersionUID = 1L;
	private Logger logger = Logger.getLogger(this.getClass());

	/** HashMap con los parametros que servirán como filtros para el reporte */
	private Map<String, Object> parameters;

	/**
	 * Ruta donde se ubica el reporte como archivo jasper (en la mayoria de
	 * casos de hace referencia al reporte generico ya sea vertical u
	 * horizontal)
	 */
	private String jasperFile;

	/**
	 * Cadena de texto que define a cual tipo de archivo sera exportado el
	 * reporte
	 */
	private String typeExportFile;

	/** Nombre del reporte */
	private String reportName;

	/** Lista a cargar */
	private List<?> list;

	/** Objeto para formatear una fecha */
	private SimpleDateFormat df = new SimpleDateFormat("yyyyMMdd-hhmmss");

	
	protected InputStream getResourceInputStream(String realPath) {
		 ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
		
		
		return  externalContext
                .getResourceAsStream(realPath);
				//ServletActionContext.getServletContext().getResourceAsStream(realPath);
	}

	public void createReport() throws Exception {
		try {
			
			FacesContext context=FacesContext.getCurrentInstance();
			ServletContext servletContext=(ServletContext)context.getExternalContext().
											getContext();
			
		
			
			HttpServletResponse response=(HttpServletResponse)context.getExternalContext().
					getResponse();
			
			HttpServletRequest request=(HttpServletRequest)context.getExternalContext().
					getRequest();
			logger.info("SE COMIENZA CON EL PROCESO DE CREACION DE ARCHIVOS");
			InputStream inputStream = null;
	
			if (getJasperFile() == null || getJasperFile().equals("")) {
				throw new Exception("No se ha definido la ubicacion del archivo jasper.");
			}
			logger.info("JASPERFILE : " + getJasperFile());

			if (getTypeExportFile() == null) {
				setTypeExportFile(ConstantWebApp.ARCHIVO_PDF);
			}
			
			logger.info("TIPO DE ARCHIVO : " + getTypeExportFile());
			
			inputStream = servletContext.getResourceAsStream(getJasperFile());
			beforeCreateReport();

			JRBeanCollectionDataSource dataSource = new JRBeanCollectionDataSource(list);
			JasperPrint jasperPrint = JasperFillManager.fillReport(inputStream, parameters, dataSource);
			logger.info("EL REPORTE HA SIDO LLENADO CON DATOS");

			JRExporter exporter = null;
			PrintWriter out = null;

			// Si es que no se ha definido el tipo de archivo al cual sera
			// exportado el reporte, se
			// generara un archivo PDF.
			
			if (getReportName() == null || getReportName().equals("")) {
				Calendar hoy = new GregorianCalendar();
				setReportName("reporte-" + df.format(hoy.getTime()));
			}
			
			logger.info("NOMBRE DEL REPORTE : " + getReportName());

			if (getTypeExportFile().equals(ConstantWebApp.ARCHIVO_PDF)) {
				logger.info("SE REALIZARA LA EXPORTACION A PDF");

				response.setContentType("application/pdf");
				response.addHeader("Content-Disposition", "attachment; filename=" + getReportName() + ".pdf");

				exporter = new JRPdfExporter();
				exporter.setParameter(JRExporterParameter.JASPER_PRINT, jasperPrint);
				exporter.setParameter(JRExporterParameter.OUTPUT_STREAM, response.getOutputStream());
				exporter.exportReport();
				
				response.flushBuffer();
				response.getOutputStream().flush();
				response.getOutputStream().close();
				
			} else if (getTypeExportFile().equals(ConstantWebApp.ARCHIVO_EXCEL)) {
				logger.info("SE REALIZARA LA EXPORTACION A EXCEL");
				
				// Aun no se implementa la posibilidad de exportacion a Excel
				response.setContentType("application/vnd.ms-excel");
				response.addHeader("Content-Disposition", "attachment; filename=" + getReportName() + ".xls");

				exporter = new JRXlsExporter();
				exporter.setParameter(JRExporterParameter.JASPER_PRINT, jasperPrint);
				exporter.setParameter(JRXlsExporterParameter.IS_DETECT_CELL_TYPE, Boolean.TRUE);
				exporter.setParameter(JRXlsExporterParameter.IS_WHITE_PAGE_BACKGROUND, Boolean.TRUE);
				exporter.setParameter(JRXlsExporterParameter.IS_REMOVE_EMPTY_SPACE_BETWEEN_ROWS, Boolean.TRUE);
				exporter.setParameter(JRXlsExporterParameter.OUTPUT_STREAM, response.getOutputStream());
				exporter.exportReport();
				
				response.flushBuffer();
			} else if (getTypeExportFile().equals(ConstantWebApp.ARCHIVO_HTML)) {
				response.addHeader("imprimir", "true");
				response.setContentType("text/html");
				
				out = response.getWriter();
				exporter = new JRHtmlExporter();
				Map<String, Object> imagesMap = new HashMap<String, Object>();
				request.getSession().setAttribute("IMAGES_MAP", imagesMap);
				request.getSession().setAttribute(ImageServlet.DEFAULT_JASPER_PRINT_SESSION_ATTRIBUTE, jasperPrint);
				request.getSession().setAttribute("net.sf.jasperreports.j2ee.jasper_print", jasperPrint);
				
				exporter.setParameter(JRHtmlExporterParameter.IMAGES_MAP, imagesMap);
				exporter.setParameter(JRExporterParameter.JASPER_PRINT, jasperPrint);
				exporter.setParameter(JRExporterParameter.OUTPUT_WRITER, out);
				exporter.setParameter(JRHtmlExporterParameter.IMAGES_URI, request.getContextPath() + "/image?image=");
				exporter.exportReport();
				out.flush();
				out.close();

				return;
			} else {
				throw new Exception("Tipo de archivo para exportar el reporte es desconocido.");
			}
			context.getApplication().getStateManager().saveView(context);
			context.responseComplete();
		} catch (JRException e) {
			logger.error(e);
			throw new Exception("Error al exportar y generar la vista del reporte.");
		} catch (Exception e) {
			logger.error(e);
			throw new Exception(e.getMessage());
		}
	}

	public void beforeCreateReport() {
		logger.info("INICIO beforeCreateReport");
		if (parameters != null && typeExportFile != null) {
			if (typeExportFile.equals(ConstantWebApp.ARCHIVO_EXCEL) || typeExportFile.equals(ConstantWebApp.ARCHIVO_HTML)) {
				parameters.put("IS_IGNORE_PAGINATION", new Boolean(true));
			}
		}
		logger.info("FIN beforeCreateReport");
	}

	/**
	 * Setea el tipo de archivo al cual se exportara el jasperFile. En caso que
	 * el tipo sea nulo, se asignara PDF.
	 * 
	 * @param fileType tipo de archivo al cual se exportara
	 */
	public void setExportFileType(String fileType) {
		if (fileType == null) {
			setTypeExportFile(ConstantWebApp.ARCHIVO_PDF);
		}
		if (fileType.equals(ConstantWebApp.ARCHIVO_PDF)) {
			setTypeExportFile(ConstantWebApp.ARCHIVO_PDF);
		} else if (fileType.equals(ConstantWebApp.ARCHIVO_EXCEL)) {
			setTypeExportFile(ConstantWebApp.ARCHIVO_EXCEL);
		} else if (fileType.equals(ConstantWebApp.ARCHIVO_HTML)) {
			setTypeExportFile(ConstantWebApp.ARCHIVO_HTML);
		} else {
			setTypeExportFile(ConstantWebApp.ARCHIVO_PDF);
		}
	}

	public Map<String, Object> getParameters() {
		return parameters;
	}

	public void setParameters(Map<String, Object> parameters) {
		this.parameters = parameters;
	}

	public String getTypeExportFile() {
		return typeExportFile;
	}

	public void setTypeExportFile(String typeExportFile) {
		this.typeExportFile = typeExportFile;
	}

	public String getReportName() {
		return reportName;
	}

	public void setReportName(String reportName) {
		this.reportName = reportName;
	}

	public String getJasperFile() {
		return jasperFile;
	}

	public void setJasperFile(String jasperFile) {
		this.jasperFile = jasperFile;
	}

	public List<?> getList() {
		return list;
	}

	public void setList(List<?> list) {
		this.list = list;
	}

	
}
